/*
 * Class based on CKS.SPTagCloud
 * with new methods to get items for a tag
 * and modification in the render with pagination
 */

using System;
using System.Data;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Xml.Serialization;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using System.Collections;
using System.Globalization;
using BDF.TagCloud.Utilities;

namespace BDF.TagCloud
{
   
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:TagBrowser runat=server></{0}:TagBrowser>")]
    [XmlRoot(Namespace = "BDF.TagCloud")]
    public class TagBrowser : WebPart
    {
        
        private string tagColumnName = "Tags";
        private string noTagsMsg = SPUtility.GetLocalizedString("$Resources:NoTagsMessage", "TagCloudFeature", SPContext.Current.Web.Language);
        private string noItemsMsg = SPUtility.GetLocalizedString("$Resources:NoItemsMessage", "TagCloudFeature", SPContext.Current.Web.Language);
        private string sortField = string.Empty;
        private bool sortOrder = true;
        private static int FRAME_SIZE = 25;//used for results pagination
        private int resultCount; //used for contain the number of result for a tag
        private string tagPageURL; //initializes with current page        
        private LiteralControl lcBR=new LiteralControl("<br/>\n");

        private string[] fontSizes = new string[] { "22", "18", "14", "12", "10", "9" };

        [Bindable(true)]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("TagColumnTitle")]
        [DefaultValue("")]
        [Localizable(true)]
        public string TagColumnName
        {
            get
            {
                return ((this.tagColumnName == null) ? String.Empty : this.tagColumnName);
            }

            set
            {
                this.tagColumnName = value;
            }
        }

        [Bindable(true)]
        [DefaultValue("")]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("SortFieldTitle")]
        [LocalizedWebDescriptionAttribute("SortFieldDesc")]
        public string SortField // 
        {
            get
            {
                return this.sortField;
            }
            set
            {
                this.sortField = value;
            }
        }

        [Bindable(true)]
        [DefaultValue(true)]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("SortOrderTitle")]
        [LocalizedWebDescriptionAttribute("SortOrderDesc")]
        public bool SortOrder
        {
            get
            {
                return this.sortOrder;
            }
            set
            {
                this.sortOrder = value;
            }
        }

        protected override void RenderWebPart(HtmlTextWriter output)
        {
            //get current page for the next results link(pagination)
            this.tagPageURL = Page.Request.Path;

            //get the value of the tag provided by url
            string tagname = Page.Request.QueryString["tags"];
            if (String.IsNullOrEmpty(tagname))
            {
                output.Write("<br/>" + SPEncode.HtmlEncode(this.noTagsMsg) + "<br/>");
                return;
            }
            tagname = tagname.Trim().Replace("%20", " ");

            //get the first value to show the results (pagination)
            string paramStart = Page.Request.QueryString["start"];
            int start=0;
            try
            {
                start = int.Parse(paramStart);
            }
            catch (FormatException ex)
            {
                //conversion failed => left 0
            }
            catch (ArgumentNullException e)
            {
                //none argument => left 0
            }

            //Get items for the tag and page wished (start number)
            ArrayList arrayItems = this.GetItemsTag(tagname,start);

            String p = SPUtility.GetLocalizedString("$Resources:TagBrowserInfo", "TagCloudFeature", SPContext.Current.Web.Language);
            output.Write(p +"<br/><br/>", start+1, borneMax(start), resultCount, SPEncode.HtmlEncode(tagname) );

            if (arrayItems.Count > 0)
            {
                foreach (SPListItem item in arrayItems)
                {
                    if (item.Title == String.Empty)
                        item["Titre"] = item.Name;

                    //Icon => a star
                    LiteralControl lcIcon = new LiteralControl("<img src=\"/_layouts/images/bdf/tag.png\" alt=\"\" />");
                    this.Controls.Add(lcIcon);

                    //Title
                    LiteralControl lcTitle = new LiteralControl("<span class=\"srch-Title\">");
                    this.Controls.Add(lcTitle);                    

                    HtmlAnchor a = new HtmlAnchor();
                    //Test if it's a  doclib's item or no using the property "File" only used for a doclib
                    if(item.File==null) 
                        a.HRef = item.ParentList.ParentWeb.Url + "/" + item.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url + "?ID=" + item.ID;
                    else
                        a.HRef = item.ParentList.ParentWeb.Url + "/" + item.Url; //in the case on a doclib, url must open the document

                    a.InnerText = item.ParentList.Title + ": " + item.Title;
                    a.Title = item.Name;
                    this.Controls.Add(a);
                    

                    LiteralControl lcTitle2=new LiteralControl("</span>");
                    this.Controls.Add(lcTitle2);
                                                
                    this.Controls.Add(lcBR);                    

                    // Meta-Data...

                    // Meta-description
                    LiteralControl displaytags = null;
                    if (item.Fields.ContainsField(tagColumnName))
                    {
                        displaytags = new LiteralControl("<div class=\"srch-Description\">Tags: " + item[tagColumnName].ToString() + "</div>");
                        this.Controls.Add(displaytags);
                    }
                    
                    //Get author name
                    string auteurNom = item["Author"].ToString();
                    string auteur = auteurNom.Substring(auteurNom.IndexOf('#')+1);

                    // Meta data url
                    LiteralControl displayMeta = new LiteralControl("<p class=\"srch-Metadata\"><span class=\"srch-URL\">");
                    this.Controls.Add(displayMeta);
                    HtmlAnchor a2 = new HtmlAnchor();
                    a2.HRef = item.ParentList.ParentWeb.Url + "/" + item.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url + "?ID=" + item.ID;
                    a2.InnerText = a2.HRef;
                    a2.Title = item.Name;
                    this.Controls.Add(a2);
                    LiteralControl displayMeta2 = new LiteralControl("</span> - " + auteur + " - " + item["Modified"].ToString() + "</p>");
                    this.Controls.Add(displayMeta2);
                    
                    
                    //Rendering...

                    //icon
                    lcIcon.RenderControl(output);
                    //title
                    lcTitle.RenderControl(output);
                    a.RenderControl(output);
                    lcTitle2.RenderControl(output);
                    lcBR.RenderControl(output);
                    //description
                    if (null != displaytags) { displaytags.RenderControl(output); }
                    //meta-data
                    displayMeta.RenderControl(output);
                    a2.RenderControl(output);
                    displayMeta2.RenderControl(output);
                    
                }

                //Pagination...
                //Show links => 10 pages maximum
                int pageCourante = (start / FRAME_SIZE) + 1;
                int pageMax = (resultCount / FRAME_SIZE) + 1;
                int lienMin = pageCourante - 5;
                int lienMax = pageCourante + 5;

                //Recovery of ptential errors
                if (lienMin < 1)
                {
                    lienMax = lienMax + Math.Abs(lienMin);
                    lienMin = 1;
                }
                if (lienMax > pageMax)
                    lienMax = pageMax;

                //Get the value of PrecPage and NextPage
                String prec = SPUtility.GetLocalizedString("$Resources:PrecPage", "TagCloudFeature", SPContext.Current.Web.Language);
                String suiv = SPUtility.GetLocalizedString("$Resources:NextPage", "TagCloudFeature", SPContext.Current.Web.Language);

                output.Write("<div class=\"srch-Page srch-Page-bg\">");
                
                //Test if PrecPage has to be shown
                if (pageCourante > 1)
                    output.Write("<a href=" + this.tagPageURL + "?tags=" + tagname + "&start=" + (start - FRAME_SIZE).ToString() + ">" + prec + "</a> ");
                //Show the page links
                for (int i = lienMin; i < lienMax; i++)
                {
                    if (i == pageCourante)
                        output.Write(" <b>"+i+"</b>");
                    else
                        output.Write(" <a href=" + this.tagPageURL + "?tags=" + tagname + "&start=" + ((i - 1) * FRAME_SIZE).ToString() + ">" + i + "</a>");
                }
                //Test if NextPage has to be shown
                if (pageCourante < pageMax)
                    output.Write(" <a href=" + this.tagPageURL + "?tags=" +tagname + "&start=" + (start + FRAME_SIZE).ToString() + ">"+suiv+"</a>");
                output.Write("</div>");
            }
            else
            {
                output.Write("<br/>" + SPEncode.HtmlEncode(this.noItemsMsg) + "<br/>");
            }
        }

        //Get all items for the tag(parameter) and for the range start with "start"(parameter)
        protected ArrayList GetItemsTag(string tagName,int start)
        {
            DataTable table = LaunchQuery(0, tagName);//request on lists
            DataTable table2 = LaunchQuery(1, tagName);//request on doclib

            table.Merge(table2);//merge results of two request

            resultCount = table.Rows.Count; //update of resultcount

            ArrayList result = new ArrayList(); // will contains items object

            SPSite currentSite = SPContext.Current.Site;            

            DataRow row;
            for (int i=start;i<borneMax(start);i++)
            {
                row = table.Rows[i];
                using (SPWeb currentWeb = currentSite.OpenWeb(new Guid(row[1].ToString())))
                {
                    SPList currentlist = currentWeb.Lists.GetList((new Guid(row[0].ToString())), false);
                    SPItem item = currentlist.GetItemById(int.Parse(row[2].ToString()));
                    result.Add(item);
                }
            }
            
            return result;
            
        }

        //allow to can not exceed the limit of the table 
        private int borneMax(int start)
        {
            return Math.Min(start + FRAME_SIZE, resultCount);
        }

        //launch one request on the site collection and all sites, searching items (on lists and doclibs) with "Tags" value = tagname
        protected DataTable LaunchQuery(int typeListe, string tagName)
        {
            string lists = "<Lists BaseType=\"" + typeListe + "\" />";
            string viewFields = "<FieldRef Name=\"Tags\" />";
            string webs = "<Webs Scope=\"Recursive\" />";
            CrossListQueryInfo query = new CrossListQueryInfo();
            query.RowLimit = 10000;
            query.WebUrl = SPContext.Current.Site.ServerRelativeUrl;
            query.Lists = lists;
            query.Webs = webs;
            query.Query = "<Where><Contains><FieldRef Name=\"Tags\" /><Value Type=\"Text\">" + tagName + "</Value></Contains></Where>";
            query.ViewFields = viewFields;

            // adding the Order By tags
            string OrderByFieldRefFormatString = "<FieldRef Name=\"{0}\" Ascending=\"{1}\" />";
            string OrderByTagFormatString = "<OrderBy>{0}</OrderBy>";
            if (!String.IsNullOrEmpty(this.sortField))
            {
                string orderbyClause = String.Format(OrderByFieldRefFormatString, this.sortField, this.SortOrder);
                orderbyClause = String.Format(OrderByTagFormatString, orderbyClause);
                query.Query += orderbyClause;
            }

            query.UseCache = true;//use the cache for optimize results

            CrossListQueryCache cache = new CrossListQueryCache(query);

            return cache.GetSiteData(SPContext.Current.Site);
        }    


    }

}
